// AWTScrollPane.cpp: implementation of the AWTScrollPane class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "awt.h"
#include "AWTScrollPane.h"
#include "AWTScrollPanePeer.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

IMPLEMENT_DYNAMIC(AWTScrollPane, AWTContainer)

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

AWTScrollPane::AWTScrollPane()
{
	construct(SCROLLBARS_AS_NEEDED);
}

AWTScrollPane::AWTScrollPane(int scrollbarDisplayPolicy)
{
	construct(scrollbarDisplayPolicy);
}

AWTScrollPane::~AWTScrollPane()
{

}

void AWTScrollPane::addImpl(AWTComponent* comp, CString& constraints, int index)
{
  if (getComponentCount() > 0) 
	{
		remove(0);
	}
	if (index > 0) 
	{
		return;
	}
  AWTContainer::addImpl(comp, constraints, index);
}

CSize AWTScrollPane::getViewportSize() 
{
	AWTInsets i = getInsets();
	return CSize(m_w - i.right - i.left, m_h - i.top - i.bottom);
}

int AWTScrollPane::getHScrollbarHeight() 
{
	int h = 0;
	if (m_scrollbarDisplayPolicy != SCROLLBARS_NEVER) 
	{
		AWTScrollPanePeer* peer = (AWTScrollPanePeer*)m_peer;
		if (peer != NULL) 
		{
			h = peer->getHScrollbarHeight();
		}
	}
	return h;
}

int AWTScrollPane::getVScrollbarWidth() 
{
	int w = 0;
	if (m_scrollbarDisplayPolicy != SCROLLBARS_NEVER) 
	{
	  AWTScrollPanePeer* peer = (AWTScrollPanePeer*)m_peer;
	  if (peer != NULL) 
		{
			w = peer->getVScrollbarWidth();
	  }
	}
	return w;
}

void AWTScrollPane::setScrollPosition(int x, int y) 
{
	if (m_ncomponents <= 0)
		return;
	m_hAdjustable->setValue(x);
	m_vAdjustable->setValue(y);
}

CPoint AWTScrollPane::getScrollPosition() 
{
	if (m_ncomponents <= 0) 
		return CPoint();
	return CPoint(m_hAdjustable->getValue(), m_vAdjustable->getValue()); 
}

CSize AWTScrollPane::calculateChildSize() 
{
	AWTComponent* c = getComponent(0);
	CSize cs(c->getPreferredSize());
	CSize size = getSize();
	int vbarWidth = getVScrollbarWidth(); 
	int hbarHeight = getHScrollbarHeight();
	AWTInsets i = getInsets();
	BOOL vbarOn = ((i.left + i.right) >= vbarWidth);
	BOOL hbarOn = ((i.top + i.bottom) >= hbarHeight);
	int viewWidth = size.cx - (i.left + i.right) - 
			(vbarOn ? 0 : vbarWidth);
	int viewHeight = size.cy - (i.top + i.bottom) - 
			(hbarOn ? 0 : hbarHeight);
	BOOL hbarNeeded = (cs.cx > viewWidth);
	BOOL vbarNeeded = (cs.cy > viewHeight);
	
	if (cs.cx < viewWidth) 
	{
		cs.cx = viewWidth + (vbarNeeded ? 0 : vbarWidth);
	}
	if (cs.cy < viewHeight) 
	{
		cs.cy = viewHeight + (hbarNeeded ? 0 : hbarHeight);
	}
	return cs;
}

void AWTScrollPane::layout() 
{
	if (m_ncomponents > 0) 
	{
	  AWTComponent* c = getComponent(0);
	  CPoint p = c->getLocation();
	  CSize cs = calculateChildSize();
	  CSize vs = getViewportSize();	

	  // update the child
	  int xPos = (cs.cx > vs.cx ? min(-p.x, cs.cx - vs.cx) : -p.x);
	  int yPos = (cs.cy > vs.cy ? min(-p.y, cs.cy - vs.cy) : -p.y);
	  c->reshape(-xPos, -yPos, cs.cx, cs.cy);
	  AWTScrollPanePeer* peer = (AWTScrollPanePeer*)m_peer;
	  if (peer != NULL) 
		{
			peer->childResized(cs.cx, cs.cy);
	  }

	  // update adjustables... the viewport size may have changed
	  // with the scrollbars coming or going so the viewport size
	  // is updated before the adjustables.
	  vs = getViewportSize();
	  m_hAdjustable->setSpan(0, cs.cx, vs.cx);
	  m_vAdjustable->setSpan(0, cs.cy, vs.cy);
	}
}

CWnd* AWTScrollPane::createComponent()
{
	CWnd* wParent = getParent()->getPeer();
	if (wParent == NULL)
		return NULL;
	CWnd* pwnd = new AWTScrollPanePeer(this);	 
	pwnd->Create(NULL, _T("AWT Panel Window"), WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, 
		getBounds(), wParent, 100);
	if (!m_enabled)
		pwnd->EnableWindow(FALSE);
	return pwnd;
}

CSize AWTScrollPane::getPreferredSize() 
{
	return CSize(100,100);
}

///////////////////////////////////////////////////////////////////////

void PeerFixer::adjustmentValueChanged(AWTAdjustmentEvent* e) 
{
	AWTAdjustable* adj = e->getAdjustable();
	int value = e->getValue();
	AWTScrollPanePeer* peer = (AWTScrollPanePeer*)m_scroller->getPeer();
	if (peer != NULL) 
	{
		peer->setValue(adj, value);
	}
  AWTComponent* c = m_scroller->getComponent(0);
	  
	switch (adj->getOrientation()) 
	{
	  case AWTAdjustable::VERTICAL:
			c->move(c->getLocation().x, -(value));
			break;
	  case AWTAdjustable::HORIZONTAL:
			c->move(-(value), c->getLocation().y);
			break;
  }
}

///////////////////////////////////////////////////////////////////////

void ScrollPaneAdjustable::setSpan(int min, int max, int visible)
{
	// adjust the values to be reasonable
	m_minimum = min;
	m_maximum = max(max, m_minimum + 1);
	m_visibleAmount = min(visible, m_maximum - m_minimum);
	m_visibleAmount = max(m_visibleAmount, 1);
  m_blockIncrement = max((int)(visible * .90), 1);
	setValue(m_value);
}

void ScrollPaneAdjustable::setUnitIncrement(int u) 
{
	if (u != m_unitIncrement) 
	{
	  m_unitIncrement = u;
	  if (m_sp->getPeer() != NULL) 
		{
			AWTScrollPanePeer* peer = (AWTScrollPanePeer*)m_sp->getPeer();
			peer->setUnitIncrement(this, u);
	  }
	}
} 

void ScrollPaneAdjustable::setValue(int v) 
{
	// bounds check
	v = max(v, m_minimum);
	v = min(v, m_maximum - m_visibleAmount);
  if (v != m_value) 
	{
	  m_value = v;
	  // Synchronously notify the listeners so that they are 
	  // guaranteed to be up-to-date with the Adjustable before
	  // it is mutated again.
	  AWTAdjustmentEvent e(this, AWTAdjustmentEvent::ADJUSTMENT_VALUE_CHANGED, AWTAdjustmentEvent::TRACK, m_value);
	  m_adjustmentListener->adjustmentValueChanged(&e);
	}
}


